/**
 * 
 * @brief  bsp_spi.c
 * @param  None
 * 
 * @author xhq
 * @date   2024/11/05
 * 
 */
/* include */
#include "bsp_spi.h"

/* define */

/* typedef */

/* global varibles */
spi_dev_type g_spi_dev_info ={
	.spi_mode = 0,
    .spi_speed = 20000000,
    .spi_bits = 8,
    .spi_delay = 0,
	//两个斯凯瑞丽的RC8088，使用soc_spi0片选成两个spidev，同一时刻，只能有一个SPI发送数据 spidev1.0 远端 spidev1.1 近端
	.dev_info[0].dev_name = "/dev/spidev1.0",
	.dev_info[0].fd = -1,
	.dev_info[1].dev_name = "/dev/spidev1.1",
	.dev_info[1].fd = -1,
};
/* private function */


void buf_printf(char *dsrt,uint8_t *buf,uint32_t len)
{
	printf("%s:%d:",dsrt,len);
	for(int i=0;i<len;i++){
		printf("%.2x ",buf[i]);
	}
	printf("\n");
}

/* function */
/**
 * @brief 网络模块初始化
 * 
 * @param None ：
 * 
 * @return uint32_t ：0：正常，非0：错误代码
 * 
 * @note：
 */
uint32_t bsp_spi_init(void)
{
    uint32_t l_u32_ret = 0;
	uint32_t l_u32_i;
	uint32_t request_mode;
	for(l_u32_i=0;l_u32_i<SPI_NUM_MAX;l_u32_i++)
	{
		g_spi_dev_info.dev_info[l_u32_i].fd = open(g_spi_dev_info.dev_info[l_u32_i].dev_name,O_RDWR); 
		if(g_spi_dev_info.dev_info[l_u32_i].fd < 0)
		{
			SET_ERROR_CODE(l_u32_ret, 0);
            goto error;
		}
		/*
		* spi mode
		*/
		/* WR is make a request to assign 'mode' */
		request_mode = g_spi_dev_info.spi_mode;
		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_WR_MODE32, &g_spi_dev_info.spi_mode) < 0)
		{
			printf("can't set spi mode");
			SET_ERROR_CODE(l_u32_ret, 1);
            goto error;
		}
			
		/* RD is read what mode the device actually is in */
		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_RD_MODE32, &g_spi_dev_info.spi_mode) < 0)
		{
			printf("can't get spi mode");
			SET_ERROR_CODE(l_u32_ret, 2);
            goto error;
		}
			
		/* Drivers can reject some mode bits without returning an error.
		* Read the current value to identify what mode it is in, and if it
		* differs from the requested mode, warn the user.
		*/
		if (request_mode != g_spi_dev_info.spi_mode)
		{
			printf("WARNING device does not support requested mode 0x%x\n",
				request_mode);
			SET_ERROR_CODE(l_u32_ret, 3);
			goto error;
		}


		/*
		* bits per word
		*/
		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_WR_BITS_PER_WORD, &g_spi_dev_info.spi_bits) < 0 )
		{	
			printf("can't set bits per word");
			SET_ERROR_CODE(l_u32_ret, 4);
			goto error;
		}

		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_RD_BITS_PER_WORD, &g_spi_dev_info.spi_bits) < 0 )
		{
			printf("can't get bits per word");
			SET_ERROR_CODE(l_u32_ret, 5);
			goto error;
		}
		/*
		* max speed hz
		*/
		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_WR_MAX_SPEED_HZ, &g_spi_dev_info.spi_speed) < 0 )
		{
			printf("can't set max speed hz");
			SET_ERROR_CODE(l_u32_ret, 6);
			goto error;
		}
		if(ioctl(g_spi_dev_info.dev_info[l_u32_i].fd, SPI_IOC_RD_MAX_SPEED_HZ, &g_spi_dev_info.spi_speed)< 0 )
		{
			printf("can't get max speed hz");
			SET_ERROR_CODE(l_u32_ret, 7);
			goto error;
		}
			
		printf("spi mode: 0x%x\n", g_spi_dev_info.spi_mode);
		printf("bits per word: %u\n", g_spi_dev_info.spi_bits);
		printf("max speed: %u Hz (%u kHz)\n", g_spi_dev_info.spi_speed, g_spi_dev_info.spi_speed/1000);
	}

	error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}

uint32_t bsp_spi_read(void)
{
    uint32_t l_u32_ret = 0;

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}

uint32_t bsp_spi_write(void)
{
    uint32_t l_u32_ret = 0;

    error:
    RETURN_ERROR_CODE(l_u32_ret, __func__);
}

uint32_t spi_read(int fd,uint8_t *rx_buf, uint32_t rx_len)
{   
	return read(fd,rx_buf,rx_len);
}

uint32_t spi_write(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *tx_buf, uint32_t tx_len)
{
    int ret;
    uint8_t m_tx_buf[SPI_RECIEVE_BUF_MAX_LEN];
    int m_tx_len = 0;
    memcpy(m_tx_buf,cmd_buf,cmd_len);
	m_tx_len+=cmd_len;

	if(tx_len){
    	memcpy(&m_tx_buf[cmd_len],tx_buf,tx_len);
		m_tx_len+=tx_len;
	}

    ret = write(fd,m_tx_buf,m_tx_len);
    return ret;
}


uint32_t spi_write_crc(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *tx_buf, uint32_t tx_len, uint8_t *crc_buf)
{
    int ret;
    uint8_t m_tx_buf[SPI_RECIEVE_BUF_MAX_LEN];
    int m_tx_len = 0;
	
    memcpy(m_tx_buf,cmd_buf,cmd_len);
	m_tx_len+=cmd_len;
	if(tx_len){
		memcpy(&m_tx_buf[cmd_len],tx_buf,tx_len);
		m_tx_len+=tx_len;
	}
	if(crc_buf){
		memcpy(&m_tx_buf[cmd_len+tx_len],crc_buf,2);
		m_tx_len+=2;
	}
    	
    ret = write(fd,m_tx_buf,m_tx_len);
	if(ret > 0)
		return 0;
	else
	    return ret;
}

uint32_t spi_transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
	int ret = 0;
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = len,
		.delay_usecs = g_spi_dev_info.spi_delay,
		.speed_hz = g_spi_dev_info.spi_speed,
		.bits_per_word = g_spi_dev_info.spi_bits,
	};

	if (g_spi_dev_info.spi_mode & SPI_TX_OCTAL)
		tr.tx_nbits = 8;
	else if (g_spi_dev_info.spi_mode & SPI_TX_QUAD)
		tr.tx_nbits = 4;
	else if (g_spi_dev_info.spi_mode & SPI_TX_DUAL)
		tr.tx_nbits = 2;
	if (g_spi_dev_info.spi_mode & SPI_RX_OCTAL)
		tr.rx_nbits = 8;
	else if (g_spi_dev_info.spi_mode & SPI_RX_QUAD)
		tr.rx_nbits = 4;
	else if (g_spi_dev_info.spi_mode & SPI_RX_DUAL)
		tr.rx_nbits = 2;
	if (!(g_spi_dev_info.spi_mode & SPI_LOOP)) {
		if (g_spi_dev_info.spi_mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
			tr.rx_buf = 0;
		else if (g_spi_dev_info.spi_mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL))
			tr.tx_buf = 0;
	}

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1){
		printf("can't send spi message:%d\n",ret);
		return ret;
	}
	return 0;
}

uint32_t spi_read_transfer_crc(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *rx_buf, uint32_t rx_len, uint8_t *crc_buf)
{
	int ret;
	uint32_t len; 
	if(crc_buf ==NULL){
		len = cmd_len + rx_len;
	}else{
		len = cmd_len + rx_len+2;
	}	
	uint8_t tx[len];
	uint8_t rx[len];
	
	memset(tx,0,sizeof(tx));
	memset(rx,0,sizeof(rx));
	memcpy(tx,cmd_buf,cmd_len);
//	buf_printf("send",tx,len);
//	printf("+++++++++++++%d:%d++++++++\n",fd,g_spi_dev_info.dev_info[0].fd);
	ret = spi_transfer(fd,tx,rx,len);
	if(ret){
		printf("spi_transfer err!ret:%d\n",ret);
	}
//	buf_printf("recv",rx,len);
	memcpy(rx_buf,&rx[cmd_len],rx_len);
	if(crc_buf){
		memcpy(crc_buf,&rx[cmd_len+rx_len],2);
	}
	return ret;	
}

uint32_t spi_read_transfer(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *rx_buf, uint32_t rx_len)
{
	return spi_read_transfer_crc(fd,cmd_buf,cmd_len,rx_buf,rx_len,NULL);
}

uint32_t spi_write_transfer_crc(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *tx_buf, uint32_t tx_len, uint8_t *crc_buf)
{
	int ret;
	uint32_t len; 
	if(crc_buf ==NULL){
		len = cmd_len + tx_len;
	}else{
		len = cmd_len + tx_len+2;
	}		
	uint8_t tx[len];
	uint8_t rx[len];
	memset(tx,0,sizeof(tx));
	memset(rx,0,sizeof(rx));
	memcpy(tx,cmd_buf,cmd_len);
	if(tx_len){
		memcpy(&tx[cmd_len],tx_buf,tx_len);
	}
	if(crc_buf){
		memcpy(&tx[cmd_len+tx_len],crc_buf,2);
	}
//	buf_printf("write:",tx,len);
	return spi_transfer(fd,tx,rx,len);
}

uint32_t spi_write_transfer(int fd,uint8_t *cmd_buf, uint8_t cmd_len, uint8_t *tx_buf, uint32_t tx_len)
{
	return spi_write_transfer_crc(fd,cmd_buf,cmd_len,tx_buf,tx_len,NULL);
}

void close_spi(int fd)
{
    close(fd);
}


